# Load Libraries
packages <- c(
  'ggplot2','tidyverse','plotly','leaflet',
  'shiny','shinyWidgets','shinydashboard',
  'xts','forecast','TTR',
  'DT','lubridate','RColorBrewer','scales','stopwords',
  'tidytext','stringr','wordcloud','wordcloud2',
  'SnowballC','textmineR','topicmodels','textclean','tm'
)
for (package in packages) { 
  if (!require(package, character.only = T, quietly = T)) {
    install.packages(package)
    library(package, character.only = T)
  }
}
# Load data
crm <- read_csv("CRM_interacions_table.csv")
gift <- read_csv("gift_transactions_table.csv")
video <- read_csv("video_email_data_table.csv")
constituent <- read_csv("constituent_profiles_table.csv")

Data Exploration

CRM Data Overview

# CRM Interaction Type
g <- crm %>%
        group_by(CRM_INTERACTION_TYPE) %>%
        summarise(Total = n()) %>%
        select(CRM_INTERACTION_TYPE, Total) %>%
        ggplot(aes(x = reorder(CRM_INTERACTION_TYPE,Total) ,y = Total))  +
        geom_bar(stat = "identity",width = 0.5, fill='black')  +
        scale_y_continuous(labels = scales::comma) +
        labs(x ="CRM Interaction Type", y = "Count") + coord_flip() +
        theme(legend.text = element_text(size = 12),
              legend.title = element_text(size = 12),
              axis.title = element_text(size = 14),
              axis.text = element_text(size = 12))
      
ggplotly(g)

CRM Interaction Over Time

crm <- crm %>%
        mutate(Year = lubridate::year(CRM_INTERACTION_DATE),
               Quarter = lubridate::quarter(CRM_INTERACTION_DATE),
               Month = lubridate::month(CRM_INTERACTION_DATE, label = TRUE),
               DOW = lubridate::wday(CRM_INTERACTION_DATE, label=TRUE))

CRM Interaction by Year

crm_year <- crm %>%
group_by(Year, CRM_INTERACTION_TYPE) %>%
        summarise(Total = n()) %>%
        select(Year,CRM_INTERACTION_TYPE, Total)

   g <- ggplot(crm_year, aes(as.factor(Year), Total, group=CRM_INTERACTION_TYPE, colour = CRM_INTERACTION_TYPE)) + 
      geom_line( linewidth=1) + theme_minimal() +
      labs(x = "Year", y = "Total", color="CRM Interaction Type") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

CRM Interaction by Quarter

crm %>%
group_by(Quarter, CRM_INTERACTION_TYPE) %>%
        summarise(Total = n()) %>%
        select(Quarter,CRM_INTERACTION_TYPE, Total) %>% 
      ggplot(aes(as.factor(Quarter), Total, group=CRM_INTERACTION_TYPE, colour = CRM_INTERACTION_TYPE)) + 
      geom_line( linewidth=1) + theme_minimal() +
      labs(x = "Quarter", y = "Total", color="CRM Interaction Type") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))

CRM Interaction by Month

crm %>%
group_by(Month, CRM_INTERACTION_TYPE) %>%
        summarise(Total = n()) %>%
        select(Month,CRM_INTERACTION_TYPE, Total) %>% 
      ggplot(aes(as.factor(Month), Total, group=CRM_INTERACTION_TYPE, colour = CRM_INTERACTION_TYPE)) + 
      geom_line( linewidth=1) + theme_minimal() +
      labs(x = "Quarter", y = "Total", color="CRM Interaction Type") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))

CRM Interaction by Day of Week

crm %>%
group_by(DOW, CRM_INTERACTION_TYPE) %>%
        summarise(Total = n()) %>%
        select(DOW,CRM_INTERACTION_TYPE, Total) %>% 
      ggplot(aes(as.factor(DOW), Total, group=CRM_INTERACTION_TYPE, colour = CRM_INTERACTION_TYPE)) + 
      geom_line( linewidth=1) + theme_minimal() +
      labs(x = "Day of Week", y = "Total", color="CRM Interaction Type") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))

Gift Overview

Gifts overtime

gift <- gift %>%
        mutate(Year = lubridate::year(GIFT_DATE),
               Quarter = lubridate::quarter(GIFT_DATE),
               Month = lubridate::month(GIFT_DATE, label = TRUE),
               DOW = lubridate::wday(GIFT_DATE, label=TRUE))

Gift by Year

g <- gift %>%
group_by(Year) %>%
        summarise(Total = sum(AMOUNT)) %>%
        select(Year, Total) %>% 
        na.omit() %>%
      ggplot(aes(Year, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Year", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 90, hjust = 1))
ggplotly(g)

Gift by Quarter

g <- gift %>%
group_by(Quarter) %>%
        summarise(Total = sum(AMOUNT)) %>%
        select(Quarter, Total) %>% 
        na.omit() %>%
      ggplot(aes(Quarter, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Quarter", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

Gift by Month

g <- gift %>%
group_by(Month) %>%
        summarise(Total = sum(AMOUNT)) %>%
        select(Month, Total) %>% 
        na.omit() %>%
      ggplot(aes(Month, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Month", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

Gift by Day of Week

g <- gift %>%
group_by(DOW) %>%
        summarise(Total = sum(AMOUNT)) %>%
        select(DOW, Total) %>% 
        na.omit() %>%
      ggplot(aes(DOW, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Day of Week", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

Video Overview

Video Views over time

video <- video %>%
        mutate(Year = lubridate::year(SENT_DATE),
               Quarter = lubridate::quarter(SENT_DATE),
               Month = lubridate::month(SENT_DATE, label = TRUE),
               DOW = lubridate::wday(SENT_DATE, label=TRUE))

Video views by year

g <- video %>%
group_by(Year) %>%
        summarise(Total = sum(VIDEO_VIEWS)) %>%
        select(Year, Total) %>% 
        na.omit() %>%
      ggplot(aes(as.factor(Year), Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Year", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

Video Views by Quarter

g <- video %>%
group_by(Quarter) %>%
        summarise(Total = sum(VIDEO_VIEWS)) %>%
        select(Quarter, Total) %>% 
        na.omit() %>%
      ggplot(aes(Quarter, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Quarter", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

Video Views by Month

g <- video %>%
group_by(Month) %>%
        summarise(Total = sum(VIDEO_VIEWS)) %>%
        select(Month, Total) %>% 
        na.omit() %>%
      ggplot(aes(Month, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Month", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)

Video Views by Day of Week

g <- video %>%
group_by(DOW) %>%
        summarise(Total = sum(VIDEO_VIEWS)) %>%
        select(DOW, Total) %>% 
        na.omit() %>%
      ggplot(aes(DOW, Total)) + 
      geom_bar(stat = "identity",width = 0.5, fill='black') + theme_minimal() +
      labs(x = "Day of the week", y = "Total") + 
      scale_y_continuous(labels = comma) +
      theme(legend.text = element_text(size = 10),
            legend.title = element_text(size = 10),
            axis.title = element_text(size = 10),
            axis.text = element_text(size = 10),
            axis.text.x = element_text(angle = 0, hjust = 1))
ggplotly(g)
LS0tCnRpdGxlOiAiQXByYSBEYXRhIFNjaWVuY2UgQ2hhbGxlbmdlIDIwMjUiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQojIExvYWQgTGlicmFyaWVzCnBhY2thZ2VzIDwtIGMoCiAgJ2dncGxvdDInLCd0aWR5dmVyc2UnLCdwbG90bHknLCdsZWFmbGV0JywKICAnc2hpbnknLCdzaGlueVdpZGdldHMnLCdzaGlueWRhc2hib2FyZCcsCiAgJ3h0cycsJ2ZvcmVjYXN0JywnVFRSJywKICAnRFQnLCdsdWJyaWRhdGUnLCdSQ29sb3JCcmV3ZXInLCdzY2FsZXMnLCdzdG9wd29yZHMnLAogICd0aWR5dGV4dCcsJ3N0cmluZ3InLCd3b3JkY2xvdWQnLCd3b3JkY2xvdWQyJywKICAnU25vd2JhbGxDJywndGV4dG1pbmVSJywndG9waWNtb2RlbHMnLCd0ZXh0Y2xlYW4nLCd0bScKKQpmb3IgKHBhY2thZ2UgaW4gcGFja2FnZXMpIHsgCiAgaWYgKCFyZXF1aXJlKHBhY2thZ2UsIGNoYXJhY3Rlci5vbmx5ID0gVCwgcXVpZXRseSA9IFQpKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2UpCiAgICBsaWJyYXJ5KHBhY2thZ2UsIGNoYXJhY3Rlci5vbmx5ID0gVCkKICB9Cn0KYGBgCgoKYGBge3J9CiMgTG9hZCBkYXRhCmNybSA8LSByZWFkX2NzdigiQ1JNX2ludGVyYWNpb25zX3RhYmxlLmNzdiIpCmdpZnQgPC0gcmVhZF9jc3YoImdpZnRfdHJhbnNhY3Rpb25zX3RhYmxlLmNzdiIpCnZpZGVvIDwtIHJlYWRfY3N2KCJ2aWRlb19lbWFpbF9kYXRhX3RhYmxlLmNzdiIpCmNvbnN0aXR1ZW50IDwtIHJlYWRfY3N2KCJjb25zdGl0dWVudF9wcm9maWxlc190YWJsZS5jc3YiKQpgYGAKCiMgRGF0YSBFeHBsb3JhdGlvbgoKIyMgQ1JNIERhdGEgT3ZlcnZpZXcKYGBge3J9CiMgQ1JNIEludGVyYWN0aW9uIFR5cGUKZyA8LSBjcm0gJT4lCiAgICAgICAgZ3JvdXBfYnkoQ1JNX0lOVEVSQUNUSU9OX1RZUEUpICU+JQogICAgICAgIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lCiAgICAgICAgc2VsZWN0KENSTV9JTlRFUkFDVElPTl9UWVBFLCBUb3RhbCkgJT4lCiAgICAgICAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihDUk1fSU5URVJBQ1RJT05fVFlQRSxUb3RhbCkgLHkgPSBUb3RhbCkpICArCiAgICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKwogICAgICAgIGxhYnMoeCA9IkNSTSBJbnRlcmFjdGlvbiBUeXBlIiwgeSA9ICJDb3VudCIpICsgY29vcmRfZmxpcCgpICsKICAgICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkKICAgICAgCmdncGxvdGx5KGcpCmBgYAoKCiMjIyBDUk0gSW50ZXJhY3Rpb24gT3ZlciBUaW1lCmBgYHtyfQpjcm0gPC0gY3JtICU+JQogICAgICAgIG11dGF0ZShZZWFyID0gbHVicmlkYXRlOjp5ZWFyKENSTV9JTlRFUkFDVElPTl9EQVRFKSwKICAgICAgICAgICAgICAgUXVhcnRlciA9IGx1YnJpZGF0ZTo6cXVhcnRlcihDUk1fSU5URVJBQ1RJT05fREFURSksCiAgICAgICAgICAgICAgIE1vbnRoID0gbHVicmlkYXRlOjptb250aChDUk1fSU5URVJBQ1RJT05fREFURSwgbGFiZWwgPSBUUlVFKSwKICAgICAgICAgICAgICAgRE9XID0gbHVicmlkYXRlOjp3ZGF5KENSTV9JTlRFUkFDVElPTl9EQVRFLCBsYWJlbD1UUlVFKSkKYGBgCgojIyMjIENSTSBJbnRlcmFjdGlvbiBieSBZZWFyCmBgYHtyfQpjcm1feWVhciA8LSBjcm0gJT4lCmdyb3VwX2J5KFllYXIsIENSTV9JTlRFUkFDVElPTl9UWVBFKSAlPiUKICAgICAgICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JQogICAgICAgIHNlbGVjdChZZWFyLENSTV9JTlRFUkFDVElPTl9UWVBFLCBUb3RhbCkKCiAgIGcgPC0gZ2dwbG90KGNybV95ZWFyLCBhZXMoYXMuZmFjdG9yKFllYXIpLCBUb3RhbCwgZ3JvdXA9Q1JNX0lOVEVSQUNUSU9OX1RZUEUsIGNvbG91ciA9IENSTV9JTlRFUkFDVElPTl9UWVBFKSkgKyAKICAgICAgZ2VvbV9saW5lKCBsaW5ld2lkdGg9MSkgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiWWVhciIsIHkgPSAiVG90YWwiLCBjb2xvcj0iQ1JNIEludGVyYWN0aW9uIFR5cGUiKSArIAogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxKSkKZ2dwbG90bHkoZykKYGBgCgojIyMjIENSTSBJbnRlcmFjdGlvbiBieSBRdWFydGVyCmBgYHtyfQpjcm0gJT4lCmdyb3VwX2J5KFF1YXJ0ZXIsIENSTV9JTlRFUkFDVElPTl9UWVBFKSAlPiUKICAgICAgICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JQogICAgICAgIHNlbGVjdChRdWFydGVyLENSTV9JTlRFUkFDVElPTl9UWVBFLCBUb3RhbCkgJT4lIAogICAgICBnZ3Bsb3QoYWVzKGFzLmZhY3RvcihRdWFydGVyKSwgVG90YWwsIGdyb3VwPUNSTV9JTlRFUkFDVElPTl9UWVBFLCBjb2xvdXIgPSBDUk1fSU5URVJBQ1RJT05fVFlQRSkpICsgCiAgICAgIGdlb21fbGluZSggbGluZXdpZHRoPTEpICsgdGhlbWVfbWluaW1hbCgpICsKICAgICAgbGFicyh4ID0gIlF1YXJ0ZXIiLCB5ID0gIlRvdGFsIiwgY29sb3I9IkNSTSBJbnRlcmFjdGlvbiBUeXBlIikgKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCgpgYGAKCiMjIyMgQ1JNIEludGVyYWN0aW9uIGJ5IE1vbnRoCmBgYHtyfQpjcm0gJT4lCmdyb3VwX2J5KE1vbnRoLCBDUk1fSU5URVJBQ1RJT05fVFlQRSkgJT4lCiAgICAgICAgc3VtbWFyaXNlKFRvdGFsID0gbigpKSAlPiUKICAgICAgICBzZWxlY3QoTW9udGgsQ1JNX0lOVEVSQUNUSU9OX1RZUEUsIFRvdGFsKSAlPiUgCiAgICAgIGdncGxvdChhZXMoYXMuZmFjdG9yKE1vbnRoKSwgVG90YWwsIGdyb3VwPUNSTV9JTlRFUkFDVElPTl9UWVBFLCBjb2xvdXIgPSBDUk1fSU5URVJBQ1RJT05fVFlQRSkpICsgCiAgICAgIGdlb21fbGluZSggbGluZXdpZHRoPTEpICsgdGhlbWVfbWluaW1hbCgpICsKICAgICAgbGFicyh4ID0gIk1vbnRoIiwgeSA9ICJUb3RhbCIsIGNvbG9yPSJDUk0gSW50ZXJhY3Rpb24gVHlwZSIpICsgCiAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEpKQpgYGAKCgojIyMjIENSTSBJbnRlcmFjdGlvbiBieSBEYXkgb2YgV2VlawpgYGB7cn0KY3JtICU+JQpncm91cF9ieShET1csIENSTV9JTlRFUkFDVElPTl9UWVBFKSAlPiUKICAgICAgICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JQogICAgICAgIHNlbGVjdChET1csQ1JNX0lOVEVSQUNUSU9OX1RZUEUsIFRvdGFsKSAlPiUgCiAgICAgIGdncGxvdChhZXMoYXMuZmFjdG9yKERPVyksIFRvdGFsLCBncm91cD1DUk1fSU5URVJBQ1RJT05fVFlQRSwgY29sb3VyID0gQ1JNX0lOVEVSQUNUSU9OX1RZUEUpKSArIAogICAgICBnZW9tX2xpbmUoIGxpbmV3aWR0aD0xKSArIHRoZW1lX21pbmltYWwoKSArCiAgICAgIGxhYnMoeCA9ICJEYXkgb2YgV2VlayIsIHkgPSAiVG90YWwiLCBjb2xvcj0iQ1JNIEludGVyYWN0aW9uIFR5cGUiKSArIAogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxKSkKYGBgCiMjIEdpZnQgT3ZlcnZpZXcKIyMjIEdpZnRzIG92ZXJ0aW1lCmBgYHtyfQpnaWZ0IDwtIGdpZnQgJT4lCiAgICAgICAgbXV0YXRlKFllYXIgPSBsdWJyaWRhdGU6OnllYXIoR0lGVF9EQVRFKSwKICAgICAgICAgICAgICAgUXVhcnRlciA9IGx1YnJpZGF0ZTo6cXVhcnRlcihHSUZUX0RBVEUpLAogICAgICAgICAgICAgICBNb250aCA9IGx1YnJpZGF0ZTo6bW9udGgoR0lGVF9EQVRFLCBsYWJlbCA9IFRSVUUpLAogICAgICAgICAgICAgICBET1cgPSBsdWJyaWRhdGU6OndkYXkoR0lGVF9EQVRFLCBsYWJlbD1UUlVFKSkKYGBgCgojIyMjIEdpZnQgYnkgWWVhcgpgYGB7cn0KZyA8LSBnaWZ0ICU+JQpncm91cF9ieShZZWFyKSAlPiUKICAgICAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0oQU1PVU5UKSkgJT4lCiAgICAgICAgc2VsZWN0KFllYXIsIFRvdGFsKSAlPiUgCiAgICAgICAgbmEub21pdCgpICU+JQogICAgICBnZ3Bsb3QoYWVzKFllYXIsIFRvdGFsKSkgKyAKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiWWVhciIsIHkgPSAiVG90YWwiKSArIAogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KGcpCmBgYAoKIyMjIyBHaWZ0IGJ5IFF1YXJ0ZXIKYGBge3J9CmcgPC0gZ2lmdCAlPiUKZ3JvdXBfYnkoUXVhcnRlcikgJT4lCiAgICAgICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKEFNT1VOVCkpICU+JQogICAgICAgIHNlbGVjdChRdWFydGVyLCBUb3RhbCkgJT4lIAogICAgICAgIG5hLm9taXQoKSAlPiUKICAgICAgZ2dwbG90KGFlcyhRdWFydGVyLCBUb3RhbCkpICsgCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLHdpZHRoID0gMC41LCBmaWxsPSdibGFjaycpICsgdGhlbWVfbWluaW1hbCgpICsKICAgICAgbGFicyh4ID0gIlF1YXJ0ZXIiLCB5ID0gIlRvdGFsIikgKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KGcpCmBgYAoKR2lmdCBieSBNb250aApgYGB7cn0KZyA8LSBnaWZ0ICU+JQpncm91cF9ieShNb250aCkgJT4lCiAgICAgICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKEFNT1VOVCkpICU+JQogICAgICAgIHNlbGVjdChNb250aCwgVG90YWwpICU+JSAKICAgICAgICBuYS5vbWl0KCkgJT4lCiAgICAgIGdncGxvdChhZXMoTW9udGgsIFRvdGFsKSkgKyAKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiTW9udGgiLCB5ID0gIlRvdGFsIikgKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KGcpCmBgYAoKR2lmdCBieSBEYXkgb2YgV2VlawpgYGB7cn0KZyA8LSBnaWZ0ICU+JQpncm91cF9ieShET1cpICU+JQogICAgICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bShBTU9VTlQpKSAlPiUKICAgICAgICBzZWxlY3QoRE9XLCBUb3RhbCkgJT4lIAogICAgICAgIG5hLm9taXQoKSAlPiUKICAgICAgZ2dwbG90KGFlcyhET1csIFRvdGFsKSkgKyAKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiRGF5IG9mIFdlZWsiLCB5ID0gIlRvdGFsIikgKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KGcpCmBgYAoKIyMgVmlkZW8gT3ZlcnZpZXcKIyMjIFZpZGVvIFZpZXdzIG92ZXIgdGltZQpgYGB7cn0KdmlkZW8gPC0gdmlkZW8gJT4lCiAgICAgICAgbXV0YXRlKFllYXIgPSBsdWJyaWRhdGU6OnllYXIoU0VOVF9EQVRFKSwKICAgICAgICAgICAgICAgUXVhcnRlciA9IGx1YnJpZGF0ZTo6cXVhcnRlcihTRU5UX0RBVEUpLAogICAgICAgICAgICAgICBNb250aCA9IGx1YnJpZGF0ZTo6bW9udGgoU0VOVF9EQVRFLCBsYWJlbCA9IFRSVUUpLAogICAgICAgICAgICAgICBET1cgPSBsdWJyaWRhdGU6OndkYXkoU0VOVF9EQVRFLCBsYWJlbD1UUlVFKSkKYGBgCgojIyMjIFZpZGVvIHZpZXdzIGJ5IHllYXIKYGBge3J9CmcgPC0gdmlkZW8gJT4lCmdyb3VwX2J5KFllYXIpICU+JQogICAgICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bShWSURFT19WSUVXUykpICU+JQogICAgICAgIHNlbGVjdChZZWFyLCBUb3RhbCkgJT4lIAogICAgICAgIG5hLm9taXQoKSAlPiUKICAgICAgZ2dwbG90KGFlcyhhcy5mYWN0b3IoWWVhciksIFRvdGFsKSkgKyAKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiWWVhciIsIHkgPSAiVG90YWwiKSArIAogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxKSkKZ2dwbG90bHkoZykKYGBgCgojIyMjIFZpZGVvIFZpZXdzIGJ5IFF1YXJ0ZXIKYGBge3J9CmcgPC0gdmlkZW8gJT4lCmdyb3VwX2J5KFF1YXJ0ZXIpICU+JQogICAgICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bShWSURFT19WSUVXUykpICU+JQogICAgICAgIHNlbGVjdChRdWFydGVyLCBUb3RhbCkgJT4lIAogICAgICAgIG5hLm9taXQoKSAlPiUKICAgICAgZ2dwbG90KGFlcyhRdWFydGVyLCBUb3RhbCkpICsgCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLHdpZHRoID0gMC41LCBmaWxsPSdibGFjaycpICsgdGhlbWVfbWluaW1hbCgpICsKICAgICAgbGFicyh4ID0gIlF1YXJ0ZXIiLCB5ID0gIlRvdGFsIikgKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KGcpCmBgYAoKIyMjIyBWaWRlbyBWaWV3cyBieSBNb250aApgYGB7cn0KZyA8LSB2aWRlbyAlPiUKZ3JvdXBfYnkoTW9udGgpICU+JQogICAgICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bShWSURFT19WSUVXUykpICU+JQogICAgICAgIHNlbGVjdChNb250aCwgVG90YWwpICU+JSAKICAgICAgICBuYS5vbWl0KCkgJT4lCiAgICAgIGdncGxvdChhZXMoTW9udGgsIFRvdGFsKSkgKyAKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiTW9udGgiLCB5ID0gIlRvdGFsIikgKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KGcpCmBgYAoKIyMjIyBWaWRlbyBWaWV3cyBieSBEYXkgb2YgV2VlawpgYGB7cn0KZyA8LSB2aWRlbyAlPiUKZ3JvdXBfYnkoRE9XKSAlPiUKICAgICAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0oVklERU9fVklFV1MpKSAlPiUKICAgICAgICBzZWxlY3QoRE9XLCBUb3RhbCkgJT4lIAogICAgICAgIG5hLm9taXQoKSAlPiUKICAgICAgZ2dwbG90KGFlcyhET1csIFRvdGFsKSkgKyAKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsd2lkdGggPSAwLjUsIGZpbGw9J2JsYWNrJykgKyB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHggPSAiRGF5IG9mIHRoZSB3ZWVrIiwgeSA9ICJUb3RhbCIpICsgCiAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEpKQpnZ3Bsb3RseShnKQpgYGAKCgoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgoKYGBge3J9CgpgYGAKCgo=